﻿Imports WRDB.DataWeb.NwisQwResult
Imports WRDB.DataWeb.NwisQwStation

''' <summary>
''' NWISIV: http://waterservices.usgs.gov/rest/WOF-IV-Service.html
''' See also: http://qwwebservices.usgs.gov/technical-documentation.html
''' </summary>
''' <remarks></remarks>
Public Class clsNwisQw
    Inherits clsWebProvider

    Private WithEvents NwisQWRes As New NwisQwResult.QWResultService
    Private WithEvents NwisQWSta As New NwisQwStation.QWStationService

    'note: web services are problematic; use REST instead
    Private BaseURL As String = "http://qwwebservices.usgs.gov"

    Public Overrides ReadOnly Property Description As String
        Get
            Return "The USGS NWIS (U.S. Geological Survey National Water Information System) provides native access to USGS water quality data. For more information about NWIS, see the NWIS home page at http://waterdata.usgs.gov/nwis."
        End Get
    End Property

    Public Overrides ReadOnly Property URL As String
        Get
            Return "http://waterdata.usgs.gov/nwis"
        End Get
    End Property

    Public Function GetStationsWebService(Optional NameFilter As String = "") As Boolean
        Try
            LastException = Nothing
            Cancelled = False
            Dim gs As New NwisQwStation.getStations
            With AreaOfInterest
                gs.BBox = New String() {String.Format("{0},{1},{2},{3}", .Left, .Top, .Right, .Bottom)}
                'gs.Statecode = New String() {"GA"}
            End With

            Dim Orgs() As NwisQwStation.OrganizationDataType
            Try
                Orgs = NwisQWSta.getStations(gs)
            Catch ex As Exception
                Return False
            End Try
            For Each O As NwisQwStation.OrganizationDataType In Orgs
                Dim AgencyID As String = O.OrganizationDescription.OrganizationIdentifier
                Dim AgencyName As String = TestNull(O.OrganizationDescription.OrganizationFormalName, "")
                For Each M As NwisQwStation.MonitoringLocationDataType In O.MonitoringLocation
                    Dim SiteID As String = M.MonitoringLocationIdentity.MonitoringLocationIdentifier
                    Dim StaName As String = M.MonitoringLocationIdentity.MonitoringLocationName
                    Dim StaType As String = M.MonitoringLocationIdentity.MonitoringLocationTypeName
                    Dim Latitude As String = M.MonitoringLocationGeospatial.LatitudeMeasure
                    Dim Longitude As String = M.MonitoringLocationGeospatial.LongitudeMeasure
                    Dim StationID As String = SiteID
                    Dim HUC As String = TestNull(M.MonitoringLocationIdentity.HUCTwelveDigitCode, "")
                    If Not dictStations.ContainsKey(SiteID) Then
                        If NameFilter.Trim = "" OrElse StaName.ToUpper.Contains(NameFilter.Trim.ToUpper) Then
                            dictStations.Add(SiteID.Trim, New clsStation(SiteID, StationID, StaName, StaType, AgencyID, AgencyName, Latitude, Longitude, "", HUC))
                        End If
                    End If
                    If Not dictAgencies.ContainsKey(AgencyID) Then dictAgencies.Add(AgencyID, New clsAgency(AgencyID, AgencyName))
                Next
            Next
            Return True
        Catch ex As Exception
            LastException = ex
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Get Stations
    ''' </summary>
    ''' <param name="NameFilter"></param>
    Public Overrides Function GetStations(Optional NameFilter As String = "") As Boolean
        Cancelled = False
        Dim ds As DataSet = Nothing

        Dim dsCharType As DataSet = Nothing
        If Not DownloadNwisData("http://qwwebservices.usgs.gov/Codes/CharacteristicType", dsCharType) OrElse dsCharType Is Nothing Then Return False
        Dim lstCharType As New Generic.List(Of String)
        For Each r As DataRow In dsCharType.Tables(0).Rows
            lstCharType.Add(r.Item(0))
        Next
        lstCharType.Sort()

        dictStations.Clear()
        dictAgencies.Clear()

        'try this because if char type not included, get tons of stations for which there are no data
        For Each ct As String In lstCharType
            SetProgress(lstCharType.IndexOf(ct), lstCharType.Count - 1, String.Format("Getting stations having {0} data... ({1} so far)", ct, dictStations.Count))
            With AreaOfInterest
                Dim url As String = String.Format("{0}/Station/search?bBox={1},{2},{3},{4}&characteristicType={5}&mimeType=xml", BaseURL, .Left, .Top, .Right, .Bottom, ct)
                If Not DownloadNwisData(url, ds) OrElse ds Is Nothing Then Return False
            End With

            'following is very similar to code found in clsDataStoretStaXML

            If ds.Tables.Count > 0 Then
                For Each drOrganization As DataRow In ds.Tables("Organization").Rows
                    Dim AgencyID As String = ""
                    Dim AgencyName As String = ""
                    For Each drOrganizationDescription As DataRow In drOrganization.GetChildRows("Organization_OrganizationDescription")
                        AgencyID = GetValue(drOrganizationDescription, "OrganizationIdentifier")
                        AgencyName = GetValue(drOrganizationDescription, "OrganizationFormalName")
                    Next
                    For Each drMonitoringLocation As DataRow In drOrganization.GetChildRows("Organization_MonitoringLocation")
                        Dim MonLocIdent As String = ""
                        Dim MonLocName As String = ""
                        Dim MonLocType As String = ""
                        Dim MonLocID As String = ""
                        Dim Latitude As String = ""
                        Dim Longitude As String = ""
                        Dim HUC As String = ""
                        Dim FipsCode As String = ""
                        Dim Elev As String = ""
                        For Each drMonitoringLocationIdentity As DataRow In drMonitoringLocation.GetChildRows("MonitoringLocation_MonitoringLocationIdentity")
                            MonLocIdent = GetValue(drMonitoringLocationIdentity, "MonitoringLocationIdentifier")
                            MonLocName = GetValue(drMonitoringLocationIdentity, "MonitoringLocationName")
                            MonLocType = GetValue(drMonitoringLocationIdentity, "MonitoringLocationTypeName")
                            HUC = GetValue(drMonitoringLocationIdentity, "HUCEightDigitCode")
                        Next
                        For Each drMonitoringLocationGeospatial As DataRow In drMonitoringLocation.GetChildRows("MonitoringLocation_MonitoringLocationGeospatial")
                            Latitude = GetValue(drMonitoringLocationGeospatial, "LatitudeMeasure")
                            Longitude = GetValue(drMonitoringLocationGeospatial, "LongitudeMeasure")
                            FipsCode = GetValue(drMonitoringLocationGeospatial, "StateCode") & GetValue(drMonitoringLocationGeospatial, "CountyCode")
                            For Each drVerticalMeasure As DataRow In drMonitoringLocationGeospatial.GetChildRows("MonitoringLocationGeospatial_VerticalMeasure")
                                Elev = GetValue(drVerticalMeasure, "MeasureValue")
                            Next
                        Next

                        Dim StationID As String = MonLocIdent.Trim
                        If Not dictStations.ContainsKey(StationID) Then
                            If NameFilter.Trim = "" OrElse MonLocName.ToUpper.Contains(NameFilter.Trim.ToUpper) Then
                                dictStations.Add(StationID.Trim, New clsStation(StationID, StationID, MonLocName, MonLocType, AgencyID, AgencyName, Latitude, Longitude, FipsCode, HUC, Elev))
                            End If
                        End If
                        If Not dictAgencies.ContainsKey(AgencyID) Then dictAgencies.Add(AgencyID, New clsAgency(AgencyID, AgencyName))
                    Next
                Next
            End If
            Debug.Print(ct & ": " & dictStations.Count)
        Next
        Return True
    End Function

    Public Overrides Function GetParameters(Optional NameFilter As String = "") As Boolean
        Try
            LastException = Nothing
            Cancelled = False
            Dim dsCharType As DataSet = Nothing
            If Not DownloadNwisData("http://qwwebservices.usgs.gov/Codes/CharacteristicType", dsCharType) OrElse dsCharType Is Nothing Then Return False
            Dim lstCharType As New Generic.List(Of String)
            For Each r As DataRow In dsCharType.Tables(0).Rows
                lstCharType.Add(r.Item(0))
            Next
            lstCharType.Sort()

            dictParameters.Clear()
            For Each Parm As String In lstCharType
                If NameFilter = "" OrElse Parm.ToUpper.Contains(NameFilter.Trim.ToUpper) Then
                    dictParameters.Add(Parm, New clsParameter("", Parm, Parm, Parm, "", 0, Now, Now))
                End If
            Next

            'Static dsNwisParameters As DataSet = Nothing
            'If dsNwisParameters Is Nothing Then
            '    If Not DownloadNwisData("http://qwwebservices.usgs.gov/Codes/CharacteristicName", dsNwisParameters) Then Return False
            'End If

            'dictParameters.Clear()
            'For Each r As DataRow In dsNwisParameters.Tables(0).Rows
            '    Dim Parm As String = r.Item(0)
            '    If NameFilter = "" OrElse Parm.ToUpper.Contains(NameFilter.Trim.ToUpper) Then
            '        dictParameters.Add(Parm, New clsParameter("", Parm, Parm, Parm, "", 0, Now, Now))
            '    End If
            'Next
            Return True
        Catch ex As Exception
            LastException = ex
            Return False
        End Try
    End Function

    Public Overrides Function GetResults() As Boolean
        Try
            LastException = Nothing
            Cancelled = False
            DataCount = 0
            lstData.Clear()
            Dim AllSelected As Boolean = (SelectedParameters.Count = dictParameters.Count)
            Dim cnt As Integer = 0
            Dim cntMax As Integer = IIf(AllSelected, SelectedStations.Count, SelectedStations.Count * SelectedParameters.Count) - 1

            For s As Integer = 0 To SelectedStations.Count - 1
                Dim StationID As String = SelectedStations(s)

                For p As Integer = 0 To IIf(AllSelected, 0, SelectedParameters.Count - 1)

                    If Not SetProgress(cnt, cntMax, String.Format("Getting results for {0} ({1}); {2} values so far...", SelectedStations(s), IIf(AllSelected, "All Parameters", SelectedParameters(p)), DataCount)) Then Return False
                    cnt += 1

                    Dim ds As DataSet = Nothing
                    'Dim CharType As String = IIf(AllSelected, "", "&characteristicName=" & SelectedParameters(p))
                    Dim CharType As String = IIf(AllSelected, "", "&characteristicType=" & SelectedParameters(p))
                    Dim url As String = String.Format("{0}/Result/search?siteid={1}{2}&startDateLo={3:MM-dd-yyyy}&startDateHi={4:MM-dd-yyyy}&mimeType=xml", BaseURL, SelectedStations(s), CharType, StartDate, EndDate)
                    If Not DownloadNwisData(url, ds) Then Continue For

                    If ds IsNot Nothing AndAlso ds.Tables.Count > 0 Then
                        'must crawl through relations to gather up all data in dataset, converting hierachical dataset into flat data file for import
                        For Each drOrganization As Data.DataRow In ds.Tables("Organization").Rows
                            Dim Agency As String = TestNull(drOrganization.GetChildRows(ds.Relations("Organization_OrganizationDescription"))(0).Item("OrganizationIdentifier"), "")
                            Agency = Agency.Trim
                            For Each drActivity As DataRow In drOrganization.GetChildRows(ds.Relations("Organization_Activity")) 'has activity_id and organization_id, no other useful data
                                Dim DateTime As String = GetValue(drActivity.GetChildRows(ds.Relations("Activity_ActivityDescription"))(0), "ActivityStartDate")
                                For Each drResult As DataRow In drActivity.GetChildRows(ds.Relations("Activity_Result"))
                                    For Each drResultDescription As DataRow In drResult.GetChildRows(ds.Relations("Result_ResultDescription"))
                                        Dim CharName As String = GetValue(drResultDescription, "CharacteristicName")
                                        Dim SampFrac As String = GetValue(drResultDescription, "ResultSampleFractionText")
                                        Dim RCode As String = GetValue(drResultDescription, "ResultDetectionConditionText")
                                        If RCode = "Not Detected" Then RCode = "<"
                                        If RCode = "Detected Not Quantified" Then RCode = "N"
                                        Dim Result As String = ""
                                        Dim Units As String = ""
                                        For Each drResultMeasure As DataRow In drResultDescription.GetChildRows("ResultDescription_ResultMeasure")
                                            Result = GetValue(drResultMeasure, "ResultMeasureValue")
                                            Units = GetValue(drResultMeasure, "MeasureUnitCode")
                                        Next

                                        'note: probably need rcode field, but wqx doesn't supply it!
                                        'note: calling routine probably should concatenate stationID with agency like 012345+112WRD
                                        'note: calling routine will need to replace STORET long characteristic/sample fraction/unit names with pcodes
                                        Dim PCode As String = CharName.Trim & ";" & SampFrac.Trim & ";" & Units.Trim

                                        If Result <> "" Or RCode <> "" Then
                                            lstData.Add(New WRDB.Project.clsDataRecord(StationID, DateTime, PCode, Result, , RCode))
                                            DataCount += 1
                                        End If
                                    Next
                                Next
                            Next
                        Next
                    End If

                Next
            Next
            Return True
        Catch ex As Exception
            LastException = ex
            Return False
        End Try
    End Function

    Public Function GetResultsWebService() As Boolean
        Try
            LastException = Nothing
            Cancelled = False
            lstData.Clear()

            For s As Integer = 0 To SelectedStations.Count - 1
                If Not SetProgress(s, SelectedStations.Count - 1, String.Format("Getting results for {0}; {1} values so far...", SelectedStations(s), DataCount)) Then Return False
                Dim gr As New NwisQwResult.getResults
                With gr
                    .Siteid = New String() {s}

                    '.Organization = ConvertList(lstOrgID)

                    'ReDim .CharacteristicName(0)
                    'For i As Integer = 0 To lvParameters.Items.Count - 1
                    '    If lvParameters.Items(i).Checked Then .CharacteristicName(0) &= IIf(.CharacteristicName(0) = "", "", ";") & lvParameters.Items(i).Text
                    'Next

                    'following is causing error message in method so don't filter by date

                    '.StartDateLo = dtStart.Value.ToString("MM/dd/yyyy")
                    '.StartDateHi = dtEnd.Value.ToString("MM/dd/yyyy")
                End With

                Dim Org() As WRDB.DataWeb.NwisQwResult.OrganizationDataType = NwisQWRes.getResults(gr)
                If Org Is Nothing Then
                    Exit For
                Else
                    For Each O As NwisQwResult.OrganizationDataType In Org
                        For Each A As NwisQwResult.ActivityDataType In O.Activity
                            For i As Integer = 0 To A.Result.Length - 1
                                With A.Result(i).ResultDescription
                                    Dim CharName As String = .CharacteristicName
                                    Dim SampFrac As String = .ResultSampleFractionText
                                    Dim SampUnit As String = ""
                                    If .ResultMeasure IsNot Nothing Then SampUnit = TestNull(.ResultMeasure.MeasureUnitCode, "")

                                    Dim dt As String = TestNull(A.ActivityDescription.ActivityStartDate, "1/1/1900")
                                    If A.ActivityDescription.ActivityStartTime IsNot Nothing Then
                                        dt &= " " & A.ActivityDescription.ActivityStartTime.Time
                                    End If
                                    Dim datetime As Date = CDate(dt)
                                    Dim depthM As String = ""
                                    If A.ActivityDescription IsNot Nothing AndAlso A.ActivityDescription.ActivityDepthHeightMeasure IsNot Nothing Then depthM = TestNull(A.ActivityDescription.ActivityDepthHeightMeasure.MeasureValue, "")
                                    Dim rcode As String = Strings.Left(TestNull(.ResultDetectionConditionText, ""), 1)
                                    Dim result As String = ""
                                    If .ResultMeasure IsNot Nothing Then result = TestNull(.ResultMeasure.ResultMeasureValue, "")
                                    If result.Length > 0 AndAlso Not IsNumeric(result) Then 'assume has rcode before value
                                        rcode = result.Substring(0, 1)
                                        result = result.Remove(0, 1)
                                    End If

                                    Dim PCode As String = .CharacteristicName
                                    If Not dictParameters.ContainsKey(PCode) Then dictParameters.Add(PCode, New clsParameter("", PCode, PCode.ToUpper, CharName & IIf(SampFrac = "", "", ", " & SampFrac) & IIf(SampUnit = "", "", ", " & SampUnit), SampUnit, 0, Now, Now, CharName, SampFrac, SampUnit))

                                    AddValidate("WQX_CharacteristicName", CharName)
                                    AddValidate("WQX_ResultSampFraction", SampFrac)
                                    AddValidate("WQX_ResultMeasureUnit", SampUnit)

                                    lstData.Add(New WRDB.Project.clsDataRecord(s, datetime, PCode, result, , rcode, , depthM))
                                    DataCount += 1
                                End With
                            Next
                        Next
                    Next
                End If
            Next
            Return True
        Catch ex As Exception
            LastException = ex
            Return False
        End Try
    End Function

    Public Overrides Function GetResultCount(QuickCount As Boolean) As Boolean
        Try
            If SelectedParameters.Count = 0 Then Return False
            LastException = Nothing
            Cancelled = False
            If QuickCount Then DataCount = -1 : Return True

            Dim SiteID As String = ""

            For Each s As String In SelectedStations
                SiteID &= IIf(SiteID = "", "", ";") & s
            Next

            Dim gr As New getResults
            With gr
                .Siteid = New String() {SiteID}

                '.Organization = ConvertList(lstOrgID)

                'ReDim .CharacteristicName(0)
                'For i As Integer = 0 To lvParameters.Items.Count - 1
                '    If lvParameters.Items(i).Checked Then .CharacteristicName(0) &= IIf(.CharacteristicName(0) = "", "", ";") & lvParameters.Items(i).Text
                'Next

                'following is causing error message in method so don't filter by date

                '.StartDateLo = dtStart.Value.ToString("MM/dd/yyyy")
                '.StartDateHi = dtEnd.Value.ToString("MM/dd/yyyy")
            End With

            Dim Org() As NwisQwResult.OrganizationDataType = NwisQWRes.getResults(gr)
            If Org IsNot Nothing Then
                For Each O As NwisQwResult.OrganizationDataType In Org
                    If Not SetProgress(1) Then Exit For
                    For Each A As NwisQwResult.ActivityDataType In O.Activity
                        DataCount += A.Result.Length
                    Next
                Next
            End If
            Return True
        Catch ex As Exception
            LastException = ex
            Return False
        End Try
    End Function

End Class
